<?php

namespace App\Common\Util;

use App\Common\Exception\ApiMessageException;
use App\Common\Util\Lock\FileLock;
use JetBrains\PhpStorm\ExpectedValues;
use Psr\Log\LoggerInterface;
use think\Cache;
use think\console\Output;
use think\facade\Config;
use think\facade\Event;
use think\Log;
use think\Request;
use think\Session;

/**
 * hyperf 常用功能封装.
 *
 * Class Hy
 *
 * @date    2023/6/12
 */
class TP
{
    /**
     * 实列列表
     *
     * @var array
     */
    protected static array $instances = [];

    /**
     * @return mixed|RouteUtil
     * @date 2023/6/13
     */
    public static function route(): mixed
    {
        if (!isset(self::$instances['route'])) {
            self::$instances['route'] = new RouteUtil();
        }
        return self::$instances['route'];
    }

    /**
     * @return mixed|self
     */
    public static function instance(): mixed
    {
        if (!isset(self::$instances['tp'])) {
            self::$instances['tp'] = new self();
        }
        return self::$instances['tp'];
    }

    /**
     * @return \think\facade\Request|Request
     */
    public static function request(): \think\facade\Request|Request
    {
        return request();
    }

    /**
     * 日志记录
     *
     * @param mixed|null $message
     * @param string     $type
     * @param array      $context
     *
     * @return LoggerInterface|void
     */
    public static function log(
        mixed  $message = null,
        #[ExpectedValues(['emergency', 'alert', 'critical', 'error', 'warning', 'notice', 'info', 'debug',])]
        string $type = 'info',
        array  $context = [])
    {
        /** @var LoggerInterface $log */
        $log = app('log');

        if ($message === null) {
            return $log;
        }
        if ($message instanceof \Throwable) {
            $message = implode(PHP_EOL, [
                sprintf('%s in %s(%d)', $message->getMessage(), $message->getFile(), $message->getLine()),
                $message->getTraceAsString()
            ]);

            $type = "error";
        }elseif (is_array($message) || is_object($message)){
            $message = var_export($message, true);
        }

        $log->log($type, $message, $context);
    }

    /**
     * 缓存管理
     *
     * @return mixed|Cache
     */
    public static function cache(): mixed
    {
        return app('cache');
    }

    /**
     * 事件分发器
     *
     * @param string|object $event
     * @param mixed|null    $params
     * @param bool          $once
     *
     * @return mixed
     */
    public static function event(string|object $event, mixed $params = null, bool $once = false): mixed
    {
        return Event::trigger($event, $params, $once);
    }

    /**
     * Session管理
     * @return Session|mixed
     */
    public static function session(): mixed
    {
        return app('session');
    }

    /**
     * 获取配置
     *
     * @param string     $key
     * @param mixed|null $default
     *
     * @return mixed
     */
    public static function config(string $key, mixed $default = null): mixed
    {
        return Config::get($key, $default);
    }

    /**
     * 开发环境判断
     *
     * @return bool
     */
    public static function isDev(): bool
    {
        return self::config('app.app_env') === 'dev';
    }

    /**
     * @return Output
     */
    public static function commandOutput(): Output
    {
        return app(Output::class);
    }

    public static function lock(string $key, int $waitTime, callable $callback, string $failMessage = '请稍后再试')
    {
        $key = "av-" . $key;

        $lockInstance = TP::config('cache.lock') ?: FileLock::class;

        if (!$lock = $lockInstance::up($key, waitTime: $waitTime)){
            throw new ApiMessageException($failMessage);
        }

        try {
            $res = call_user_func($callback);
        } finally {
            $lock->down();
        }

        return $res;
    }
}
